/**
* @file
* @brief This file defines functions in utils.h
*/
#define _XOPEN_SOURCE // For crypt()
#include "config_parser.tab.h"
#include "utils.h"
#include "database.h"
#include <stdlib.h>
#include <stdio.h>

// updateRecord
// removeRecord
// findRecord
// containsRecord

// @note findTableName(), insertTableName() and printTableName() are defined in utils.c


/**
* @note must check if table exists before calling this function
* 4 cases
* If value is NULL but key not found, error key not found
* If value is NULL but key found, delete the key
* If Key not found, and value non Null, insert new value with key and value
* If Key found and value non Null, update key with value
* @returns -1 if key not found
* @returns 1 if inserted value
* @returns 2 if updated value
* @returns 3 if deleted value]
*/
int insertValue(char* Table, char* Key, char* Value)
{

    // Get table index
    int t_index = findTableIndex(Table);
printf ("t_index is %d\n", t_index);
    bool keyExist = false; // initialize key as not existent
    bool firstElement = false; // check if working with first element
    // Check if Key exists in table
    struct Record *p, *q, *newRecord;
    // Initialize p to point to first in table
    p = topTable.table[t_index].head;
    // If an element has already been inserted
    if (p == NULL)
        firstElement = true; // inserting first element
    while (p != NULL)
    {
        if((strcmp(Key, p->key)) == 0)
        {
            keyExist = true;
            break;
        }
        p = p->left;
    }
    //-------------------------------------
    // Here, we know if key exists or not
    //-------------------------------------
    // If Key exists
    //-------------------------------------
    if (keyExist == true)
    {
        // Case 1: Delete the key
        if (Value == NULL)
        {
            deleteRecord(Key, t_index);
            topTable.table[t_index].numRecs--;
            return 3;
        }
        // Case 2: Update key with value
        else
        {
            updateRecord(Key, Value, t_index);
	    return 2;
        }
    }
    //-------------------------------------
    // If key doesn't exist
    //-------------------------------------
    else
    {
        // Case 3: Return error key not found
        if (Value == NULL)
        {
            printf("Error: Key not found\n");
            return -1;
        }
        // Case 4: Insert new value with key and value
        else
        {
            // Create a new Record
            newRecord = createRecord(Key, Value);
            if (firstElement)
            {
                // Insert at beginning
                // append to the beginning of the head
                newRecord->left = NULL; //topTable.table[t_index]->head
                topTable.table[t_index].head = newRecord;
            }
            else
            {
                // Insert at beginning but point to next
                newRecord->left = topTable.table[t_index].head;
                topTable.table[t_index].head = newRecord;
            }
            topTable.table[t_index].numRecs++;
	    return 1;
        }
    }
    return 0;
}

/**
* @note must check if table exists before calling this function
* 4 cases
* If value is NULL but key not found, error key not found
* If value is NULL but key found, delete the key
* If Key not found, and value non Null, insert new value with key and value
* If Key found and value non Null, update key with value
* @returns -1 if key not found
* @returns 1 if inserted value
* @returns 2 if updated value
* @returns 3 if deleted value]
*/
int insertValueTok(char* Table, char* Key, char* Value, int token)
{

    // Get table index
    int t_index = findTableIndex(Table);
printf ("t_index is %d\n", t_index);
    bool keyExist = false; // initialize key as not existent
    bool firstElement = false; // check if working with first element
    // Check if Key exists in table
    struct Record *p, *q, *newRecord;
    // Initialize p to point to first in table
    p = topTable.table[t_index].head;
    // If an element has already been inserted
    if (p == NULL)
        firstElement = true; // inserting first element
    while (p != NULL)
    {
        if((strcmp(Key, p->key)) == 0)
        {
            keyExist = true;
            break;
        }
        p = p->left;
    }
    //-------------------------------------
    // Here, we know if key exists or not
    //-------------------------------------
    // If Key exists
    //-------------------------------------
    if (keyExist == true)
    {
        // Case 1: Delete the key
        if (Value == NULL)
        {
            deleteRecord(Key, t_index);
            topTable.table[t_index].numRecs--;
            return 3;
        }
        // Case 2: Update key with value
        else
        {
            return updateRecordTok(Key, Value, t_index, token);
        }
    }
    //-------------------------------------
    // If key doesn't exist
    //-------------------------------------
    else
    {
        // Case 3: Return error key not found
        if (Value == NULL)
        {
            printf("Error: Key not found\n");
            return -1;
        }
        // Case 4: Insert new value with key and value
        else
        {	if(token!=0&&token!=-1)
				return -5;	//	If token is not 0 and you try to insert new record, trans error
            // Create a new Record
            newRecord = createRecord(Key, Value);
// Encrypt the value of the record 



            if (firstElement)
            {
                // Insert at beginning
                // append to the beginning of the head
                newRecord->left = NULL; //topTable.table[t_index]->head
                topTable.table[t_index].head = newRecord;
            }
            else
            {
                // Insert at beginning but point to next
                newRecord->left = topTable.table[t_index].head;
                topTable.table[t_index].head = newRecord;
            }
            topTable.table[t_index].numRecs++;
	    return 1;
        }
    }
    return 0;
}

/**
* This function updates a value in the table and the token
* @param name is the key
* @param value is the value to be changed to
* @param t_index is the index of the sorted array table to be selected
* @return 1 if successful, 0 if error
*/
int updateRecordTok(char* name, char* value, int t_index, int token)
{
    struct Record *updateRecord;
    updateRecord = topTable.table[t_index].head;
    while (updateRecord != NULL)
    {
        if ( strcmp(updateRecord->key, name) == 0)
        {
	    if(token != updateRecord->metaRecord){
			if(token!=0)
			return -5;				// If they don't match and token not 0, its transactions err
		}
        strcpy(updateRecord->value, value);
	    updateRecord->metaRecord+=1;
            return 2;
        }
        updateRecord = updateRecord->left;
    }
    return 0; // Not found
}

/**
* assumes table exists
*/
int getValue(char* Table, char* Key, char* Value, int* tokenOut)
{
    // Get table index
    int t_index = findTableIndex(Table);
    bool keyExist = false; // initialize key as not existent
    bool firstElement = false; // check if working with first element
    // Check if Key exists in table
    struct Record *p, *q, *newRecord;
    // Initialize p to point to first in table
    p = topTable.table[t_index].head;
    // If an element has already been inserted
    while (p != NULL)
    {
        if((strcmp(Key, p->key)) == 0)
        {
            keyExist = true;
            break;
        }
        p = p->left;
    }
    //-------------------------------------
    // Here, we know if key exists or not
    //-------------------------------------
    // If Key exists
    //-------------------------------------
    if (keyExist == true)
    {
        // Case 1: Get the key
        getRecord(Table,  Key, Value, t_index, tokenOut);
        return 1;
    }
    //-------------------------------------
    // If key doesn't exist
    //-------------------------------------
    else
    {
        // Case 2: Return error key not found
        printf("Error: Key not found\n");
        return -1;
    }
    return 0;
}

/**
* This function gets a record from the Table data structure
* @param Table is the table to get
* @param Key is the key to get
* @param t_index is the index of this table in the sorted array of tables
* @return 1 if successful, 0 if error
*/
// TODO: Needs updating
void getRecord(char* Table, char* Key, char* Value, int t_index, int* tokenOut)
{
    struct Record *getRecord;
    getRecord = topTable.table[t_index].head;
    while (getRecord != NULL)
    {
        if (strcmp(getRecord->key, Key) == 0)
        {
            strcpy(Value, getRecord->value);
	    *tokenOut = getRecord->metaRecord;
        }
/* printf("Key: %s with Value: %s\n", getRecord->name, getRecord->value);*/
        getRecord = getRecord->left;
    }
    return; // Not found
}

/**
* This function deletes a record with key called name
* @param name the key to be deleted
* @param t_index is the index of this key in the table
* @returns 1 if successful and 0 if error
*/
int deleteRecord(char* name, int t_index)
{
    struct Record *deleteRecord, *temp;
    deleteRecord = topTable.table[t_index].head;
    temp = deleteRecord;
    int count = 0;
    while (deleteRecord != NULL)
    {
        if ( strcmp(deleteRecord->key, name) == 0)
        {
            struct Record **prev;
            for (prev = &temp; *prev && *prev != deleteRecord; prev = &(*prev)->left)
            {
                count++;
                continue;
            }

            if (*prev) // If we are at pp
            {

                if (count == 0)
                {
                    // if deleting first element
                    temp = (*prev)->left;
                    free(topTable.table[t_index].head);
                    topTable.table[t_index].head = temp;
                    return 1;
                }
                temp = (*prev)->left; // t points to pp->next
                free(*prev); // free pp
                *prev = temp; // let pointer pointing to pp point to next
                return 1;
            }
        }
        deleteRecord = deleteRecord->left;
    }
    return 0; // Not found
}

/**
* This funciton prints all record in a chosen table
* t_index is the index of the table in the linked list to be chosen from
*/
void printRecord(int t_index)
{
    struct Record *printRecord;
    printRecord = topTable.table[t_index].head;
    while (printRecord != NULL)
    {
        printf("Key: %s with Value: %s\n", printRecord->key, printRecord->value);
        printRecord = printRecord->left;
    }
    return; // Not found
}



/**
* This funciton prints all record in a chosen table
* t_index is the index of the table in the linked list to be chosen from
*/
void printRecordEncrypted(int t_index)
{
    struct Record *printRecord;
    printRecord = topTable.table[t_index].head;
    while (printRecord != NULL)
    {
        printf("Key: %s with Value: %s\n", printRecord->key, printRecord->value);
        printRecord = printRecord->left;
    }
    return; // Not found
}

/**
* This function updates a value in the table and the token
* @param name is the key
* @param value is the value to be changed to
* @param t_index is the index of the sorted array table to be selected
* @return 1 if successful, 0 if error
*/
int updateRecord(char* name, char* value, int t_index)
{
    struct Record *updateRecord;
    updateRecord = topTable.table[t_index].head;
    while (updateRecord != NULL)
    {
        if ( strcmp(updateRecord->key, name) == 0)
        {
            strcpy(updateRecord->value, value);
	    updateRecord->metaRecord+=1;
            return 2;
        }
        updateRecord = updateRecord->left;
    }
    return 0; // Not found
}

/**
* This is the constructor for creating a new record
* @param name of the new record
* @param value of the new record
* @return A new record structure
*/
struct Record* createRecord(char* name, char* value)
{
    struct Record *newRecord;
    newRecord = (struct Record *) malloc (sizeof(struct Record));
    newRecord->left = NULL;
    newRecord->metaRecord = rand() % 1000 + 1;	// New records get random meta token
    strcpy(newRecord->key, name);
    strcpy(newRecord->value, value);
    return newRecord;
};

/**
* This function finds and checks if a table exists in a given function
* It returns the table index number
*/
int findTableIndex(char* tname)
{
printf("In findTableIndex: topTable.numTables is %d\n", topTable.numTables);
    int i = 0;
    for (i = 0; i < topTable.numTables; i++)
    {
        if( (strcmp(tname, topTable.table[i].name)) == 0)
        {
            return i; // table name found
        }
    }
    return 0; // table name not found
}



/**
* create the array table to store the table information
*/
void initializeSortedArrayTable()
{
    topTable.numTables = 0;
    return;
}



/**
* This function sorts the table array using bubble sort
*/
int sortTable()
{
    int i = 0, j = 0;
    char temp[MAX_TABLE_LEN + 1];
    for (i = 0; i < topTable.numTables; i++)
    {
        for (j = 0; j < topTable.numTables - i - 1; j++)
        {
            if ( strcmp(topTable.table[j].name,topTable.table[j+1].name ) > 0)
            {
                // Swap them
                // @note: Only swaps the names and not the values since this is a 1 time function
                // that is called after configuration file is read
                strcpy(temp,topTable.table[j].name);
                strcpy(topTable.table[j].name,topTable.table[j+1].name);
                strcpy(topTable.table[j+1].name, temp);
            }
        }
    }
    return 1; // successful sort
}

/**
* This function queries through every data entry to see if the key fits
*/
int findKeysCopiedNum(char** predName, char** predValue, char* oper, char* tableName, char** keyOut, int max_keys, int numCol)
{

    int numKeysCopied=0;

    // Get table index
    int t_index = findTableIndex(tableName);
    bool firstElement = false; // check if working with first element
    // Check if Key exists in table
    struct Record *p, *q, *newRecord;
    // Initialize p to point to first in table
    p = topTable.table[t_index].head;
	
	int predEntry = 0;
	
	int i = 0;
	int j = 0;
	int k = 0;
	int m = 0;
	int n = 0;
	int doCopy = 1;
	int isInt = 0;
	int satisfied = 0;
	char** colName;
	char** colValue;
	char* tempArg;
	char* tempC;
	char* tempP;
	
	int predNum, compNum;
	
	while(oper[predEntry]!='\0')	//	Start by counting number of pred entries
	{
		predEntry++;
	}
	
	colName = (char**) malloc(sizeof(char**) * numCol);	// Initialize an array to store each column name
	for(i = 0; i < numCol; i++)
	{
		colName[i] = (char*) malloc(sizeof(char*) * (MAX_COLNAME_LEN+1));
	}
	
	colValue = (char**) malloc(sizeof(char**) * numCol);	// Initialize an array to store each column name
	for(i = 0; i < numCol; i++)
	{
		colValue[i] = (char*) malloc(sizeof(char*) * (MAX_COLNAME_LEN+1));
	}
	
	tempArg = (char*) malloc(sizeof(char) * (MAX_VALUE_LEN+1));
	
	
	// Go through each element
    while (p->left != NULL)
    {
	satisfied = 0;
	if((numKeysCopied)==max_keys)	//	If copied max_keys number of keys already, end
		break;
		
	strcpy(tempArg, p->value); //	Get the value for the first key
	
	parseArg(colName, tempArg, colValue, numCol);	//	Each name and value for each record is stored in each array
	
	for(i=0;i<predEntry;i++)	//	Check through each entry
	{
		isInt = 0;
		m=0;
		for(j=0;j<numCol;j++)	//	check name
		{
			if(!strcmp(predName[i],colName[j]))	//	If equal, it exists
			{
				k = j;	//	Remember which column is equal
				break;
			}
		}
		
		while(((colValue[k][m]>='0')&&(colValue[k][m]<='9'))||(colValue[k][m]=='+')||(colValue[k][m]=='-')||(colValue[k][m]==' '))
			{
				if((colValue[i][m]==' ')&&(colValue[i][m+1]!='\0')&&(colValue[i][m+1]!=' '))
					break;
				
				m++;
			}
			if(colValue[k][m]=='\0')	//	Has to be end of value for int
				isInt = 1;
		
		//	check value type and oper type
		if(isInt)	//	If int
		{
			compNum = atoi(colValue[k]);
			predNum = atoi(predValue[i]);
			
			switch(oper[i])
			{
				case '=':
					if(compNum==predNum)
						satisfied++;
					break;
				case '<':
					if(compNum < predNum)
						satisfied++;
					break;
				case '>':
					if(compNum > predNum)
						satisfied++;
					break;
				default: // should never come here
				break;
			}
		}
		else		//	If char
		{
			tempP=trimwhitespace(predValue[i]);
			tempC=trimwhitespace(colValue[k]);
			if(!strcmp(tempP,tempC))
				satisfied++;
		}
	}
	if(satisfied==predEntry)
	{
			strcpy(keyOut[numKeysCopied++],p->key);
	}
	p = p->left;
    }
	
	
//-------------------------	FREE MEMORY
	for(i = 0; i < numCol; i++)	//	Free colName
	{
		free(colName[i]);
		colName[i]=NULL;
	}
	free(colName);
	colName=NULL;
	
	for(i = 0; i < numCol; i++)					//	Free colValue
	{
		free(colValue[i]);
		colValue[i]=NULL;
	}
	free(colValue);
	colValue=NULL;
	
	free(tempArg);
	
return numKeysCopied;
}

/**
* This function queries through every data entry to see if the key fits
*/
int findKeys(char** predName, char** predValue, char* oper, char* tableName, char** keyOut, int max_keys, int numCol)
{

    int numKeysCopied=0;

    // Get table index
    int t_index = findTableIndex(tableName);
    bool firstElement = false; // check if working with first element
    // Check if Key exists in table
    struct Record *p, *q, *newRecord;
    // Initialize p to point to first in table
    p = topTable.table[t_index].head;
	
	int predEntry = 0;
	
	int i = 0;
	int j = 0;
	int k = 0;
	int m = 0;
	int n = 0;
	int doCopy = 1;
	int isInt = 0;
	int satisfied = 0;
	char** colName;
	char** colValue;
	char* tempArg;
	char* tempC;
	char* tempP;
	
	int predNum, compNum;
	
	while(oper[predEntry]!='\0')	//	Start by counting number of pred entries
	{
		predEntry++;
	}
	
	colName = (char**) malloc(sizeof(char**) * numCol);	// Initialize an array to store each column name
	for(i = 0; i < numCol; i++)
	{
		colName[i] = (char*) malloc(sizeof(char*) * (MAX_COLNAME_LEN+1));
	}
	
	colValue = (char**) malloc(sizeof(char**) * numCol);	// Initialize an array to store each column name
	for(i = 0; i < numCol; i++)
	{
		colValue[i] = (char*) malloc(sizeof(char*) * (MAX_COLNAME_LEN+1));
	}
	
	tempArg = (char*) malloc(sizeof(char) * (MAX_VALUE_LEN+1));
	
	
	// Go through each element
    while (p->left != NULL)
    {
	satisfied = 0;
	if((numKeysCopied)==max_keys)	//	If copied max_keys number of keys already, end
		doCopy = 0;
		
	strcpy(tempArg, p->value); //	Get the value for the first key
	
	parseArg(colName, tempArg, colValue, numCol);	//	Each name and value for each record is stored in each array
	
	for(i=0;i<predEntry;i++)	//	Check through each entry
	{
		isInt = 0;
		m=0;
		for(j=0;j<numCol;j++)	//	check name
		{
			if(!strcmp(predName[i],colName[j]))	//	If equal, it exists
			{
				k = j;	//	Remember which column is equal
				break;
			}
		}
		
		while(((colValue[k][m]>='0')&&(colValue[k][m]<='9'))||(colValue[k][m]=='+')||(colValue[k][m]=='-')||(colValue[k][m]==' '))
			{
				if((colValue[i][m]==' ')&&(colValue[i][m+1]!='\0')&&(colValue[i][m+1]!=' '))
					break;
				
				m++;
			}
			if(colValue[k][m]=='\0')	//	Has to be end of value for int
				isInt = 1;
		
		//	check value type and oper type
		if(isInt)	//	If int
		{
			compNum = atoi(colValue[k]);
			predNum = atoi(predValue[i]);
			
			switch(oper[i])
			{
				case '=':
					if(compNum==predNum)
						satisfied++;
					break;
				case '<':
					if(compNum < predNum)
						satisfied++;
					break;
				case '>':
					if(compNum > predNum)
						satisfied++;
					break;
				default: // should never come here
				break;
			}
		}
		else		//	If char
		{
			tempP=trimwhitespace(predValue[i]);
			tempC=trimwhitespace(colValue[k]);
			if(!strcmp(tempP,tempC))
				satisfied++;
		}
	}
	if(satisfied==predEntry)
	{
		if(doCopy)
			strcpy(keyOut[numKeysCopied++],p->key);
		else
			numKeysCopied++;
	}
	p = p->left;
    }
	
	
//-------------------------	FREE MEMORY
	for(i = 0; i < numCol; i++)	//	Free colName
	{
		free(colName[i]);
		colName[i]=NULL;
	}
	free(colName);
	colName=NULL;
	
	for(i = 0; i < numCol; i++)					//	Free colValue
	{
		free(colValue[i]);
		colValue[i]=NULL;
	}
	free(colValue);
	colValue=NULL;
	
	free(tempArg);
	
return numKeysCopied;
}
// MACRO HEIGHT
// An expression for one more than the height of a node in an AVL tree
// (evaluates to 0 if node == NULL).
// Side-effects:  evaluates its argument more thfan once
// #define HEIGHT(node) ((node) ? (node)->height : 0) // TODO: For M3

//---------------------
// Utility
//--------------------


/**
* This function processes one line in the configuration file
* @note This function is called by readconfig()
* This function is useless for Milestone 3 and is only used for Milestone 2 since everything is done in LEX/YACC
*/
int process_config_line(char *line, struct config_params *params,struct check_duplmis *check)
{
    // Ignore comments.
    if (line[0] == CONFIG_COMMENT_CHAR) // defined in util.h
	return 0;
    // Extract config parameter name and value.
    char name[MAX_CONFIG_LINE_LEN];
    char value[MAX_CONFIG_LINE_LEN];
    char extra[MAX_CONFIG_LINE_LEN];
    // Scan the str line, for the first 2 strings and store it into name and value
    // returns number of items in argument list successfully filled
    int items = sscanf(line, "%s %s %s\n", name, value, extra);
    // Line must contain 2 different parameters only
    if (items != 2)
    {
	// if the line is not an empty line
	if (items != -1)
	{
	    printf("Too much/little parameter names/values");
	    return -1;
	}
	return 0; // it is just an empty line, continue
    }
    // Process this line.
    if (strcmp(name, "server_host") == 0) // if exactly the same str
    {
	// Check if host was already given
	if((check->host)==0)
	{
	    // Copy to server_host the value
	    strncpy(params->server_host, value, sizeof params->server_host);
	    check->host = 1;
	}
	else
	{
	    printf("Repeated server_host");
	    return -1; // should let to EXIT_STATUS
	}
    }
    else if (strcmp(name, "server_port") == 0)
    {
	if((check->port)==0)
	{
	// TODO: MAKE SURE PORT NUMBER IS LESS THAN MAX_PORT_LEN
		// Copy to server port the value in int
		params->server_port = atoi(value);
		check->port = 1;
	}
	else
	{
	    printf("Repeated server_port");
	    return -1;
	}
    }
    else if (strcmp(name, "username") == 0)
    {
	if((check->username)==0)
	{
	    // Copy to username the value in str
	    strncpy(params->username, value, sizeof params->username);
	    check->username = 1;
	}
	else
	{
	    printf("Repeated username");
	    return -1;
	}
    }
    else if (strcmp(name, "password") == 0)
    {
	if((check->password)==0)
	{
	    // Copy to password the value in str
	    strncpy(params->password, value, sizeof params->password);
	    check->password = 1;
	}
	else
	{
	    printf("Repeated password\n");
	    return -1;
	}
    }

    else if (strcmp(name, "table") == 0)
     {
	// If inserting first table
	if(check->table == 0)
	{
	    if(!checkName(value))
	    {
		printf("Error: Table name error\n");
		return -1; // make sure server exits after accepting -1
	    }
	    else
	    {
		if(insertTable(value) == 0) // insert the new table
		{
		    printf("Error: insertTable not successful\n");
		    return -1;
		}
		check->table++;
	    }
	}
	// If inserting second table onwards
	else
	{
	    int i = 0;
	    // Check the table name
            if(!checkName(value))
            {
		printf("Table name error\n");
                return -1;
            }
	    // Check if it exists
	    if (findTableName(value))
	    {
		    printf("Duplicated table is %s\n", value);
		    return -1;
	    }
	    // No duplicates, insert new table
	    if(!insertTable(value)) // returns 0 if exceeded limits, returns 1 if successful
	    {
		// Will be in here if exceeded table limits
		return -1;
	    }
	    else
	    {
		check->table++;
	    }
	}
    }
    else if (strcmp(name, "data_directory") == 0)
    {
	strncpy(params->data_directory, value, sizeof params->data_directory);
    }
    // Ignore unknown configuration parameters
    else
    {
	printf("Not a valid parameter name\n");
	return -1;
    }
        return 0;
}

extern struct configuration *c; // from config_parser.y
extern FILE *yyin; // from config_parser.l
/// This function reads from the config file
// Returns 0  if successful and -1 if error occurs
int read_config(const char *config_file, struct config_params *params,struct check_duplmis *check)
{
    int error_occurred = 0; // keep track if error occurs
    // Open file for reading.
    FILE *file = fopen(config_file, "r");
    if (file == NULL)
    {
	error_occurred = 1;
	printf("File is null\n");
	return -1;
    }
    yyin = file;
    // Process the config file as long as no error has occurred and it is not the end of file
    while (!error_occurred && !feof(yyin))
    {
	if (yyparse() != 0)
	{
	    printf("Aborting WLS Parsing - Syntax Error.\n");
	    yyerror("");
	    return -1;
	}
printf("PASSED YYPARSE()\n");
	// No error occurred in parsing, check if everything is given and insert value into original structure if it is
	if (c == NULL) return -1;
	if (c->hostDone == true) 
	{
	    strncpy(params->server_host, c->host, sizeof params->server_host);
	    check->host = 1;
	}
	if (c->portDone == true) 
	{
	    params->server_port = c->port;
	    check->port = 1;

	}

	if (c->usernameDone == true) 
	{
	    strncpy(params->username, c->username, sizeof params->username);
	    check->username = 1;
	}
	if (c->passwordDone == true) 
	{
	    strncpy(params->password, c->password, sizeof params->password);
	    check->password = 1;
	}
	if (c->tableDone == true)
	{
	    check->table  = 1; 
	}

	if (c->concurrencyDone == true)
	{
	    check->concurrency = 1; 
	    params->concurrency = c->concurrency;
	}
	
	// Read a line from the file.
	char line[MAX_CONFIG_LINE_LEN];
	// reads from file (line-1) characters or until newline is found
	// and stores into line. Automatically handles null terminates
	// and returns pointer to line on success

/*
	char *l = fgets(line, sizeof line, file);
	// Process the line.
	if (l == line) // If success getting this line, do process_config_line
	{
	    if(process_config_line(line, params,check) == 0)
		continue; // do nothing
	    else
		error_occurred = 1; // an error has occurred in process_config_line
	}
	// If there was no line processed, it may be the end of file, or a commented line
	else if (!feof(file))
	    error_occurred = 1;
*/
    }
//    if((check->host)==0)
    // Check to see if all values are given
    if (!(check->host) || !(check->port) || !(check->username) || !(check->password) || !(check->table) || !(check->concurrency))
    {
	error_occurred = 1;
	printf("There are missing configuration parameters");
	printf("host %d, port %d, username %d, password %d, table %d, concurrency %d\n",check->host, check->port, check->username, check->password, check->table, check->concurrency);
    }
    return error_occurred ? -1 : 0;
   return 0;
}


/**
* This function gets a line from stdin and attach it to output with null terminating it
* @param output is the string buffer to be written on
* @param max is how long the string buffer is including '\0'
* @return 1 if successful, 0 if an error occurred such as message pasdtised in was too long
*/
int getLine(char* output, int max)
{
    int i = 0;
    char c;
    while((c = getchar()) != EOF)
    {
	output[i] = c;
	if (c == '\n')
	{
	    output[i] = '\0';
	    break;
	}
	i++;
	if (i > (max-1)) // need to -1 to keep space for '\0'
	{
	    return 0; // input size was too long
	}
    }
    return 1; // getLine was successful
}

/**
* This function gets the arguments after the message is passed through the network
* The arguments has to be "+" separated since values may contain " "
*/
int getArguments(char** arg, char* cmd)
{
    int i= 0;
    char *token, *string, *tofree;
    tofree = string = strdup(cmd);
    assert(string != NULL);
    while ( ((arg[i]) = strsep(&string, "@")) != NULL)
    {
        i++;
    }
/*
    Remember to free after calling this function,
    if free here, whatever arg points to is gone
    @note If uncomment this, will segfault
    free(tofree);
*/
    return i;
}

/**
* This function gets the arguments after the message is passed through the network
* The arguments has to be "@" separated since values may contain " "
* Jerry's version, to avoid memory issues
*/
int getArgumentsJer(char** arg, char* cmd)
{
    int i = 0;
	int j = 0;
	int k = 0;
	while(cmd[i]!='\0')
	{
		k = 0;
		while(cmd[i]!='\0'&&cmd[i]!='@')
		{
			arg[j][k++] = cmd[i++];
		}
		arg[j][k]=='\0';
		j++;
		if(cmd[i]!='\0')
			i++;
	}
	return 1;
}

/**
* This function returns the number of digits contain by number
* @param number is the integer to count number of digits
* @return the number of digits of number
*/
int numDigits(int number)
{
    int count = 0; // initialize as 0
    while (number != 0)
    {
	number /= 10;
	count++;
    }
    if (count == 0)
	count++; // make count 1
    return count;
}


/**
* This function sends all of buffer till size len to sock
*/
int sendall(const int sock, const char *buf, const size_t len)
{
    size_t tosend = len;
    while (tosend > 0)
    {
	// (sockfd to send to, buffer which contains data, amount of info, flags)
	ssize_t bytes = send(sock, buf, tosend, 0);
	if (bytes <= 0)
	    break; // send() was not successful, so stop.
	tosend -= (size_t) bytes;
	buf += bytes;
    };
    return tosend == 0 ? 0 : -1;
}

/**
* This function receives buffer from sock till size buflen and stores into buf.
*/
int recvline(const int sock, char *buf, const size_t buflen)
{
    // status returns -1 if not successful in receiving any data
    //		      0 if new line received
    int status = 0; // Return status.
    size_t bufleft = buflen;
    // while there is space in the buffer to receive
    while (bufleft > 1) // and no errors and no newline received
    {
	// Read one byte from socket
	// (sockfd to read from, buf to receive data, receive 1 data, flags)
	ssize_t bytes = recv(sock, buf, 1, 0);
	if (bytes <= 0)
	{
	    // recv() was not successful, so stop.
	    status = -1;
	    break;
	}
	else if (*buf == '\n')
	{
	// Found end of line, so stop.
	*buf = 0; // Replace end of line with a null terminator.
	status = 0;
	break;
	}
	else
	{
	    // Keep going.
	    bufleft -= 1; // decrease space left in buffer
	    buf += 1; // increment position in buffer to store data
	}
    }
    *buf = 0; // add null terminator in case it's not already there.
    return status;
}

/* READN() ARE FOR MILESTONE 3 WHEN DEADLING WITH MULTIPLE CLIENTS
// Read "n" bytes from a descriptor.
ssize_t readn(int fd, void *vptr, size_t n)
{
    size_t nleft; // number of bytes left to read
    ssize_t nread; // number of bytes read
    char *ptr;
    ptr = vptr; // let ptr point to beginning of buffer given
    nleft = n; // number of bytes to read
        if ((nread = read(fd, ptr, nleft)) < 0)
        {
            if (errno == EINTR) // if interrupted by signal
                nread = 0;        // and call read() again
            else
                return(-1);
        }
       // else if (nread == 0) // nothing left to read
       //     break;                // EOF
	// else
        nleft -= nread;// update number left to read
        ptr   += nread;// mv ptr
    return(n - nleft);        // return number of bytes read
}

// This function reads from fd and stores it in ptr
ssize_t Readn(int fd, void *ptr, size_t nbytes)
{
    ssize_t n;
    if ((n = readn(fd, ptr, nbytes)) < 0)
    {
        //perror("readn error");
        return (-1);
    }
    return(n);
}
*/


// Jerry Task 3 Begin
// Please implement this to work properly for tables and store them properly
// into the table data structure from Task 2, change the handling arguments for
// int process_config_line(char *line, struct config_params *params,struct check_duplmis *check)
// if you have to.
// so you'll need to reimplement
// i) process_config_line() cause the current sscanf() thing won't work
// ii) findTableName() (you need this to make sure no duplicates of tables on configuration file)
// iii) insertTable() (you need this to know the types of tables that exists from configuration file)
// iv)  read_config(), i am not sure why you may need to change it but if you do need to do it, do it.
// Note: If you change the function headers, please update it in utils.h as well
//----------------------
// Data structure
//----------------------
/**
* This function finds and checks if a table exists in a given function
* It returns 1 if it exists and 0 if it does not
*/
int findTableName(char* tname)
{
    int i = 0;
    for (i = 0; i < topTable.numTables; i++)
    {
        if( (strcmp(tname, topTable.table[i].name)) == 0)
        {
            return 1; // table name found
        }
    }
    return 0; // table name notge found
}

/**
* This function returns 1 if table is inserted successfully, or 0 if it fails
*/
int insertTable(char* tname)
{
    if (topTable.numTables >= MAX_TABLES )
    {
        printf("Exceed Maximum Number of tables allowed\n");
        return 0;
    }
    strcpy(topTable.table[topTable.numTables].name, tname);
    topTable.table[topTable.numTables].numRecs = 0; // initialize to 0 records
    topTable.table[topTable.numTables].head = NULL; // point BST to null initially
    topTable.numTables++;
printf("In INSERTTABLE after inserting topTable numTables is %d\n", topTable.numTables);
    return 1; // success
}

/**
* This function prints the table name in the order they are in the array
*/
void printTableName()
{
struct Record * traverseRecord;

    int i = 0;
    for (i = 0; i < topTable.numTables; i++)
    {
        printf("%s\n", topTable.table[i].name);
	traverseRecord = topTable.table[i].head;
	printf("%s\n", traverseRecord->value);
    }
    return;
}



// Jerry Task 3 End

/// To log messages
void logger(FILE *file, char *message)
{
    if (file == NULL) // No logging needed
    {
	return;
    }
    fprintf(file,"%s",message);
    fflush(file);
}

/// This function generates an encrypted password
char *generate_encrypted_password(const char *passwd, const char *salt)
{
    if(salt != NULL)
	return crypt(passwd, salt);
    else
	return crypt(passwd, DEFAULT_CRYPT_SALT);
}

/**
* This function closes a file if logger was 2
* @param logger is the logging number defined
* @param serverFile is the file to be closed, 1 is if it the serverFile, 0 if it is the clientFile
*/
void Fclose(int logger, int serverFile)
{
    if (serverFile)
    {
	if (logger == 2)
	    fclose(fileServer);
    }
    else
    {
	if (logger == 2)
	    fclose(fileClient);
    }
}

/**
* This function prints the menu to prompt the user to enter his selection
*/
void menu()
{
    printf("---------------------\n 1) Connect\n 2) Authenticate\n 3) Get\n 4) Set\n 5) Disconnect\n 6) Exit\n 7) Query\n---------------------\n");
    printf("Please enter your selection: ");
    return;
}

/**
* This is the constructor for structure check
*/
int initialCheck( struct check_duplmis *check)
{
    check->host = 0;
    check->port = 0;
    check->username = 0;
    check->password = 0;
    check->table = 0;
    return 0;
}

/**
* This function ensures that the string msg does only contains alphanumeric characters or space
* It is used for checking record values
* @return 1 if it satisfies all requirements
*         0 if it does not
*/
int checkValue(char *msg)
{
    char* checkStr = msg;
    while(*checkStr != '\0')
    {

        if (*checkStr == ' ')
            checkStr++;
        // A-Z
        else if ((*checkStr >= 65) && (*checkStr <= 90))
            checkStr++;
        // a-z
        else if ((*checkStr >= 97) && (*checkStr <= 122))
            checkStr++;
        // 0-9
        else if ((*checkStr >= 48) && (*checkStr <= 57))
            checkStr++;
		//Commas are allowed to separate different columns
		else if (*checkStr == ',')
			checkStr++;
        // If here, it is not alphanumeric or a comma
		else if (((*checkStr=='+')||(*checkStr=='-'))&&(*(checkStr+1) >= 48) && (*(checkStr+1) <= 57))
			checkStr++;
		//	If it is a hyphen followed by a number = negative number or + for positive number
        else return 0;
    }
    // Satisfy all requirements (alphanumeric characters and  spaces)
    return 1;
}

/**
* This function ensures that the string msg does only contains alphanumeric characters
* It is used for checking table names and keys
* @return 1 if it satisfies all requirements
*         0 if it does not
*/
int checkName(char *msg)
{
    char* checkStr = msg;
    while(*checkStr != '\0')
    {
        // Alphanumeric
        // A-Z
        if (*checkStr == ' ')
            return 0;
	// A-Z
        if ((*checkStr >= 65) && (*checkStr <= 90))
            checkStr++;
        // a-z
        else if ((*checkStr >= 97) && (*checkStr <= 122))
            checkStr++;
        // 0-9
        else if ((*checkStr >= 48) && (*checkStr <= 57))
            checkStr++;
        // If here, it is not alphanumeric
        else return 0;
    }
    // Satisfy all requirements (alphanumeric characters, no spaces)
    return 1;
}


//============================================
// Server Functions (Wrapper)
//============================================
/**
* This function accepts a peer socket that is trying to connect
*/
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
    int  n;
    if ((n = accept(fd, sa, salenptr)) < 0)
    {
        //perror("accept error");
        exit(1);
    }
    return(n);
}

//--------------------------------------------------------------------------------------

/**
* This function binds a host socket to the server
*/
void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
    if (bind(fd, sa, salen) < 0)
    {
        //perror("bind error");
        exit(1);
    }
}

//--------------------------------------------------------------------------------------

/**
* This function connects to a host socket
*/
int ConnectServ(int fd, const struct sockaddr *sa, socklen_t salen)
{
    int result;
    if ((result = connect(fd, sa, salen)) < 0)
    {
        //perror("connect error");
        exit (1);
    }
    return(result);
}

//--------------------------------------------------------------------------------------

/**
* This function listens for peer sockets
*/
void Listen(int fd, int backlog)
{
    if (listen(fd, backlog) < 0)
    {
        //perror("listen error");
        exit(1);
    }
}

//--------------------------------------------------------------------------------------

/**
* This function creates a socket
*/
int Socket(int family, int type, int protocol)
{
    int n;
    if ((n = socket(family, type, protocol)) < 0)
    {
        //perror("socket error");
        exit(1);
    }
    return(n);
}

//--------------------------------------------------------------------------------------

/**
* This function closes a file descriptor
*/
void Close(int fd)
{
    if (close(fd) == -1)
    {
        //perror("close error");
        exit(1);
    }
}

//--------------------------------------------------------------------------------------

/**
* This function returns the numbers of entries which corresponds to how many columns there are
*/

int getCol(char* data)
{
	int num = 0;
	int n = 0;
	while(data[n]!='\0')
	{
		n++;
		while((data[n]!='@')&&(data[n]!='\0'))
		{
		n++;
		}
		num++; 
	}
	return num;
}

//--------------------------------------------------------------------------------------

/**
* This function returns true if valid for inputting to database, false otherwise
*/

int validParam(char** config, char* arg, char** configType, int numCol)
{

int i = 0;
int j = 0;
int k = 0;
int n = 0;
int m = 0;
char numChar[3];

for(i = 0; i<numCol; i++)	// Check for numCol number of columns
{
	while(arg[k]==' ')	//	Get rid of spaces
	{
		if(arg[k]=='\0')	// Ended too early, failed
			return 0;
		k++;
	}

	while((arg[k]!=' '))	// Check if the names match one by one
	{
		if((arg[k]!=config[i][j])||(config[i][j]=='\0')){	// If the names don't match or longer than config name, failed
                        return 0;
                }
		if(arg[k]=='\0')	//	If arg already ended, then too short fai;ed
			return 0;
		if(arg[k]==',')
			return 0;
		j++; k++;
	}

	if(config[i][j]!='\0')
		return 0;	// If reached the end of arg name, but not the end of config name, failed
	
	j = 0;		// Reset j counter, which is the counter for counting config.
	
	while(arg[k]==' ')	//	Get rid of spaces
	{
		if(arg[k]=='\0')	// Ended too early, failed
			return 0;
		k++;
	}
	
	if(arg[k]==',')		//If there isn't an argument, failed
	{
		return 0;
	}
	
	n=k;	//	First char? Then can be - for negative
	if(configType[i][0]=='i'){
		while((arg[k]!=' ')&&(arg[k]!=','))	//	Get rid of the arguments
		{
			if(arg[k]=='\0'){
				if(i==(numCol-1))	// If no more terms and is last term, true
					return 1;
				else				//	Else false because ended too early
					return 0;	
				}
			if((arg[k]<48)||(arg[k]>57))	//	Is it an integer? If other chars then incorrect
			{
				if((arg[k]!='-')&&(arg[k]!='+'))
					return 0;
				if(((arg[k]=='-')||(arg[k]=='+'))&&(n!=k))	//	If it's not first char and it's '-' then failed
					return 0;
			}
			k++;
		}
	}
	
	else
	{	
		while(arg[k]!=',')	//	Get rid of the arguments
		{
			if(arg[k]=='\0')
			{
				if(i==(numCol-1))	// If no more terms and is last term, true
				{
					m=m-n+1;			//	Find out how many chars allowed, and if exceeded then fail
					numChar[0]=configType[i][1];	//	m is k index at end of argument - k index at beginning + 1
					numChar[1]=configType[i][2];	//	which gives length of argument
					numChar[2]=configType[i][3];
					n = atoi(numChar);
					if(m>n)
						return 0;
					else
						return 1;
				}
				else				//	Else false because ended too early
					return 0;	
			}
			if(arg[k]!=' ')	//	Keep track of where the last character was to deal with whitespaces
				m=k;
			k++;
		}
		m=m-n+1;			//	Find out how many chars allowed, and if exceeded then fail
		numChar[0]=configType[i][1];	//	m is k index at end of argument - k index at beginning + 1
		numChar[1]=configType[i][2];	//	which gives length of argument
		numChar[2]=configType[i][3];
		n = atoi(numChar);
		if(m>n)
			return 0;
	}
	
	while((arg[k]==' '))	// Get rid of spacing
	{
		if(arg[k]=='\0'){
			if(i==(numCol-1))	// If no more terms and is last term, true
				return 1;
			else				//	Else false because ended too early
				return 0;	
			}
		k++;
	}
	if(arg[k]!=',')		//	If not a comma
	{	if(i!=(numCol-1))	//	And not the last term
			return 0;	//	Failed
	}
	else{
	if(i==(numCol-1))		//	If last term but still comma
		return 0;		//	failed
	else
		k++;			//	Else not last term but comma, get rid of comma
	}
}

return 1;
}

//--------------------------------------------------------------------------------------

/**
* This function separates the two fields inside the table params
*/

void separateParam(char** colParam, char** colName, char** colType, int numCol)
{
	int i = 0;
	int j = 0;
	int k = 0;
	
	for(i=0;i<numCol;i++)	//	Do for all columns
	{
		k=0; j=0;
		while(colParam[i][k]!=' ')	//	Get first param until whitespace which is the name
		{
			colName[i][k]=colParam[i][k];
			k++;
		}
		colName[i][k]='\0';
		
		k++;
		
		while(colParam[i][k]!='\0')	//	Get second param which is the type either i or c(number)
		{
			colType[i][j]=colParam[i][k];
			j++; k++;
		}
		colType[i][j]='\0';
	}
	return;
}

//--------------------------------------------------------------------------------------

/**
* This function gets the predicates, returns 0 if invalid parameters
*/

int getPred(char* arg, char** column, char* oper, char** value)
{
int i = 0;
int j = 0;
int k = 0;
int n = 0;
int m = 0;

if(arg[k]=='\0') return 0;
while(arg[k]!='\0')	// Do until end
{
	j=0;
	while(arg[k]==' ')	//	Get rid of spaces
	{
		if(arg[k]=='\0')	// If first run, then no arguments too early and failed
		{
			if(i==0)
				return 0;
			else
				return 1;
		}
		k++;
	}

	while((arg[k]!=' ')&&(arg[k]!='<')&&(arg[k]!='>')&&(arg[k]!='='))	// Parse until you reach operator
	{
		if(arg[k]=='\0')	//	If arg already ended, then too short failed
			return 0;
		column[i][j]=arg[k];
		j++; k++;
	}
	column[i][j]='\0';

	if(!checkName(column[i]))	//	Check if not valid table name
		return 0;
	
	while(arg[k]==' ')	//	Get rid of spaces
	{
		if(arg[k]=='\0')	// Ended too early, failed
			return 0;
		k++;
	}
	
	oper[i]=arg[k];
	if((oper[i]!='=')&&(oper[i]!='<')&&(oper[i]!='>'))	//	Invalid operator
		return 0;
	
	k++;
		
	while(arg[k]==' ')	//	Get rid of spaces
	{
		if(arg[k]=='\0')
		{
			return 0;	//	If end then failed
		}
		k++;
	}

	
	j = 0;
	while((arg[k]!='\0')&&(arg[k]!=','))	// Keep parsing till end
	{
		if(arg[k]=='\0')	//	Fine to end now
		{
			oper[i+1]='\0';
			value[i][j]='\0';
			return 1;
		}
		value[i][j]=arg[k];
		j++; k++;
	}
	value[i][j]='\0';
	
	while(arg[k]!=','&&arg[k]!='\0')	k++;		//	Get rid of comma
    if(arg[k]!='\0')
    k++;
	i++;
}
oper[i]='\0';
return 1;
}

//--------------------------------------------------------------------------------------

/**
* This function checks if the predicate names are valid columns, 1 if fine, 0 = param error
*/

int validPredName(char** colName, char** colType, int numCol, char** predName, char** predValue, char* oper)
{
	int i = 0;
	int j = 0;
	int k = 0;
	int m = 0;
	int predEntry = 0;
	
	while(oper[predEntry]!='\0')	//	Start by counting number of pred entries
	{
		predEntry++;
	}
	
        
	for(i=0;i<predEntry;i++)	//	Check through each entry
	{
		m=0;
		for(j=0;j<numCol;j++)	//	check name
		{
			if(!strcmp(predName[i],colName[j]))	//	If equal, it exists
			{
				k = j;	//	Remember which column is equal
				break;
			}
			if(j==(numCol-1))	//	If last iteration and still not equal, invalid
				return 0;
		}
		
		//	check value type and oper type
		if(colType[k][0]=='i')	//	If int
		{
			while(((predValue[i][m]=='+')||(predValue[i][m]>=48)&&(predValue[i][m]<=57))||(predValue[i][m]=='-')||(predValue[i][m]==' '))
			{
				if(m!=0 && ((predValue[i][m]=='-')||(predValue[i][m]=='-')))	//	Only 1 -/+ allowed, at the beginning for negative numbers
                                    break;
                                
				if((predValue[i][m]==' ')&&(predValue[i][m+1]!='\0')&&(predValue[i][m+1]!=' '))
                                    break;
                                
                                m++;
                                
			}
			if(predValue[i][m]!='\0')	//	Has to be end of value for int
				return 0;
		}
		else		//	If char
		{
			if(!checkValue(predValue[i]))
				return 0;
			if(oper[i]!='=')	//	Char has to use equal sign
				return 0;
		}
	}
	return 1;
}

//--------------------------------------------------------------------------------------

/**
* This function gets name and value from the input - there are no fail cases because you should be passing a valid input
*/

void parseArg(char** colName, char* input, char** colValue, int numCol)
{

int i = 0;
int j = 0;
int k = 0;
int n = 0;
int m = 0;
char numChar[3];

for(i = 0; i<numCol; i++)	// Check for numCol number of columns
{
	while(input[k]==' ')	//	Get rid of spaces
	{
		k++;
	}

	while((input[k]!=' ')&&(input[k]!=','))	// Get the name
	{
		colName[i][j]=input[k];
		j++; k++;
	}
	colName[i][j]='\0';	//	Append with NULL

	j = 0;		// Reset j counter, which is the counter for counting config.
	
	while(input[k]==' ')	//	Get rid of spaces
	{
		k++;
	}	
	
	while((input[k]!=',')&&(input[k]!='\0'))	//	Get the value stored
	{
	colValue[i][j]=input[k];
	j++; k++;
	}
	colValue[i][j]='\0';
	j=0;
	
	if(input[k]==',')	//	Get rid of commas
		k++;
}

return 1;
}
//--------------------------------------------------------------------------------------

/**
* Online found helper function to trim whitespace before and after
*/
char *trimwhitespace(char *str)
{
	char *end;

	// Trim leading space
	while(isspace(*str)) str++;

	if(*str == 0)  // All spaces?
		return str;

	// Trim trailing space
	end = str + strlen(str) - 1;
	while(end > str && isspace(*end)) end--;

	// Write new null terminator
	*(end+1) = 0;

  return str;
}

//--------------------------------------------------------------------------------------

/**
* Get all the keys from a specific table//returnstotalrecordsfound
*/
int getAllKeys(char* tableName,char** keyOut,int max_keys)
{

    int numKeysCopied=0;

    // Get table index
    int t_index = findTableIndex(tableName);
    bool firstElement = false; // check if working with first element
    // Check if Key exists in table
    struct Record *p, *q, *newRecord;
    // Initialize p to point to first in table
    p = topTable.table[t_index].head;
	
	int predEntry = 0;
	
	int i = 0;
	int j = 0;
	int k = 0;
	int m = 0;
	int n = 0;
	int doCopy = 1;
	int isInt = 0;
	int satisfied = 0;
	char* tempC;
	char* tempP;
	
	int predNum, compNum;
	
	// Go through each element
    while (p->left != NULL)
    {
	if((numKeysCopied)==max_keys)	//	If copied max_keys number of keys already, end
		doCopy = 0;
	if(doCopy)
		strcpy(keyOut[numKeysCopied++],p->key);
	else
		numKeysCopied++;
	p = p->left;
    }
	
	
return numKeysCopied;
}

//--------------------------------------------------------------------------------------

/**
* Get all the keys from a specific table//returns numkeyscopied
*/
int getAllKeysCopiedNum(char* tableName,char** keyOut,int max_keys)
{

    int numKeysCopied=0;

    // Get table index
    int t_index = findTableIndex(tableName);
    bool firstElement = false; // check if working with first element
    // Check if Key exists in table
    struct Record *p, *q, *newRecord;
    // Initialize p to point to first in table
    p = topTable.table[t_index].head;
	
	int predEntry = 0;
	
	int i = 0;
	int j = 0;
	int k = 0;
	int m = 0;
	int n = 0;
	int doCopy = 1;
	int isInt = 0;
	int satisfied = 0;
	char* tempC;
	char* tempP;
	
	int predNum, compNum;
	
	// Go through each element
    while (p->left != NULL)
    {
	if((numKeysCopied)==max_keys)	//	If copied max_keys number of keys already, end
		break;
	strcpy(keyOut[numKeysCopied++],p->key);
	p = p->left;
    }
	
	
return numKeysCopied;
}
//--------------------------------------------------------------------------------------

/**
* Checks if same col name in multiple preds
*/

int checkPredDuplicate(char** predName, char* oper)
{
	int i = 0;
	int j = 0;
	while(oper[i]!='\0')
	{
		j = i+1;
		while(oper[j]!='\0')
		{
			if(!strcmp(predName[i],predName[j]))
				return 0;
			j++;
		}
		i++;
	}
	return 1;
}
